package com.atguigu.gmall.cart.service;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.cart.feign.GmallPmsClient;
import com.atguigu.gmall.cart.feign.GmallSmsClient;
import com.atguigu.gmall.cart.feign.GmallWmsClient;
import com.atguigu.gmall.cart.interceptor.LoginInterceptor;
import com.atguigu.gmall.cart.mapper.CartMapper;
import com.atguigu.gmall.cart.pojo.Cart;
import com.atguigu.gmall.cart.pojo.UserInfo;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.common.exception.CartException;
import com.atguigu.gmall.pms.api.GmallPmsApi;
import com.atguigu.gmall.pms.entity.SkuAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuEntity;
import com.atguigu.gmall.sms.vo.ItemSaleVo;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import springfox.documentation.spring.web.json.Json;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CartService {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    CartAsyncService cartAsyncService;
    @Autowired
    GmallPmsClient pmsClient;
    @Autowired
    GmallSmsClient smsClient;
    @Autowired
    GmallWmsClient wmsClient;

    private static final String KEY_PREFIX="cart:info:";
    private static final String PRICE_PREFIX="cart:price:";

    /**
     * 新增购物车，登录将商品放入登录后的购物车map<userId,string<skuId,cart>>，
     * 未登录将商品放入未登录购物车map<userKey,string<skuId,cart>>
     *
     *hashOps是操作对象，不是具体数据，最多是个空对象（例如new User()），hashOps.hasKey()不会报空指针
     *BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(key);
     *
     * List<Object> unloginCartJsons = unLoginHashOps.values();
     *
     *  Object o = hashOps.get(skuIdString);
     * String cartJson = hashOps.get(skuIdString).toString();
     * cart = JSON.parseObject(cartJson, Cart.class);
     */
    public void saveCart(Cart cart) {
        //传过来的skuId
        Long skuId = cart.getSkuId();
        String skuIdString = cart.getSkuId().toString();
        //传过来的count
        BigDecimal count = cart.getCount();

        String userId = getUserId();

        //hashmap  map<string,map<string,string>>的外部key
        String key= KEY_PREFIX +userId;
        // 2.判断当前用户的购物车中是否包含该记录:boundHashOps：redisTemplate.opsForHash()
        // 内层的map<skuId, cart>
        //hashOps是操作对象，不是具体数据，最多是个空对象（例如new User()），hashOps.hasKey()不会报空指针
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(key);
        if (hashOps.hasKey(skuIdString)) {
            // 包含，更新数量，通过内部key（skuId），拿到cart
            String cartJson = hashOps.get(skuIdString).toString();
             cart = JSON.parseObject(cartJson, Cart.class);
            // 数量累加
            cart.setCount(cart.getCount().add(count));
            // 把更新数量之后的cart写入redis 和 mysql
           // hashOps.put(skuIdString,cart);(if，else里都有可以提取出来)
            //cartMapper.update(cart,new UpdateWrapper<Cart>().eq("user_id",userId).eq("sku_id",skuId));
            cartAsyncService.updateCart(userId,skuId,cart);
        }else {
            // 不包含，新增一条记录
            cart.setUserId(userId);
            cart.setSkuId(skuId);
            cart.setCheck(true);
            // 查询sku的信息
            ResponseVo<SkuEntity> skuEntityResponseVo = pmsClient.querySkuById(skuId);
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if (skuEntity==null) {
                throw new CartException("商品不存在");
            }
            cart.setDefaultImage(skuEntity.getDefaultImage());
            cart.setTitle(skuEntity.getTitle());
            cart.setPrice(skuEntity.getPrice());

            // 销售属性
            ResponseVo<List<SkuAttrValueEntity>> saleAttrsResponseVo = pmsClient.querySaleAttrValueBySkuId(skuId);
            List<SkuAttrValueEntity> skuAttrValueEntities = saleAttrsResponseVo.getData();
            cart.setSaleAttrs(JSON.toJSONString(skuAttrValueEntities));
            // 库存
            ResponseVo<List<WareSkuEntity>> wareResponseVo = wmsClient.queryWareSkusBySkuId(skuId);
            List<WareSkuEntity> wareSkuEntities = wareResponseVo.getData();
            if (!CollectionUtils.isEmpty(wareSkuEntities)) {
                cart.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity -> wareSkuEntity.getStock()-wareSkuEntity.getStockLocked()>0));
            }
            // 营销信息
            ResponseVo<List<ItemSaleVo>> salesResponseVo = smsClient.querySalesBySkuId(cart.getSkuId());
            List<ItemSaleVo> itemSaleVos = salesResponseVo.getData();
            cart.setSales(JSON.toJSONString(itemSaleVos));
            // 新增到redis 和 mysql
            //hashOps.put(skuIdString,cart);(if，else里都有可以提取出来)
            //事务中，需要一个service调用另一个service（同一个service里的两个方法互调，aop会不起作用）
            //String userId给定时任务xxljob准备的
            cartAsyncService.insertCart(userId,cart);

            //加入购物车时，添加实时价格缓存
            redisTemplate.opsForValue().set(PRICE_PREFIX+cart.getSkuId(),skuEntity.getPrice().toString());
        }
        hashOps.put(skuIdString,JSON.toJSONString(cart));//(if，else里都有可以提取出来)
    }

    /**
     * 封装统一获取用户信息
     * 登录返回userId
     * 未登录返回的userKey
     * @return
     */
    private String getUserId() {
        // 1.获取登录状态：未登录-userKey 登录-userId
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        //userInfo里一定有userKey，不一定有userId
        String userId=null;
        if(userInfo.getUserId()!=null){
            // 如果用户的id不为空，说明该用户已登录，添加购物车应该以userId作为key
             userId = userInfo.getUserId().toString();
        }else {
            // 否则，说明用户未登录，以userKey作为key
             userId = userInfo.getUserKey();
        }
        return userId;
    }

    //查询购物车展示到页面中（回显购物车）
    public Cart queryCartBySkuId(Long skuId, Integer count) {
        String userId = getUserId();
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(KEY_PREFIX+userId);
        if (hashOps.hasKey(skuId.toString())) {
            String cartString = hashOps.get(skuId.toString()).toString();
            Cart cart = JSON.parseObject(cartString, Cart.class);
            cart.setCount(new BigDecimal(count));
            return cart;
        }else {
            throw new CartException("当前用户不包含该购物车记录");
        }
    }
//查询购物车
    public List<Cart> queryCarts() {
        // 1.获取userkey 查询未登录的购物车
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userKey = userInfo.getUserKey();
        String key = KEY_PREFIX+userKey;
        BoundHashOperations<String, Object, Object> unLoginHashOps =
                redisTemplate.boundHashOps(key);
        List<Object> unloginCartJsons = unLoginHashOps.values();
        List<Cart> unloginCarts =null;
        if (!CollectionUtils.isEmpty(unloginCartJsons)) {
         unloginCarts =unloginCartJsons.stream().map(Object -> {
             Cart cart = JSON.parseObject(Object.toString(), Cart.class);
             //保存实时价格
             cart.setCurrentPrice(new BigDecimal(redisTemplate.opsForValue().get(PRICE_PREFIX+cart.getSkuId())));
             return cart;

         }).collect(Collectors.toList());
        }
        // 2.获取userId，判断userId是否为空，为空说明未登录，直接返回未登录的购物车
        Long userId = userInfo.getUserId();
        if(userId==null){
            return unloginCarts;
        }
        // 3.userId不为空，合并未登录的购物车到登录状态的购物车
         key = KEY_PREFIX+userId;
        BoundHashOperations<String, Object, Object> loginHashOps = redisTemplate.boundHashOps(key);
        //未登录的购物车不为空
        if (!CollectionUtils.isEmpty(unloginCarts)) {
            // 遍历未登录的购物车，合并到登录状态的购物车中
            unloginCarts.forEach(cart->{
                BigDecimal count = cart.getCount();
                // 如果登录状态的购物车已经包含了该记录，则累加数量
                String skuIdString=  cart.getSkuId().toString();
                if (loginHashOps.hasKey(skuIdString)) {
                    String cartJson = loginHashOps.get(skuIdString).toString();
                    cart = JSON.parseObject(cartJson, Cart.class);
                    cart.setCount(cart.getCount().add(count));
                    // 保存到redis，并异步保存到mysql
                    //loginHashOps.put(skuIdString,cart);
                    cartAsyncService.updateCart(userId.toString(),cart.getSkuId(),cart);
                }else {
                    // 不包含，则新增一条记录,直接将未登录购物车里的记录的userKey改为userId
                    cart.setUserId(userId.toString());
                    //loginHashOps.put(skuIdString,cart);
                    //String userId给定时任务xxljob准备的
                    cartAsyncService.insertCart(userId.toString(),cart);
                }
                loginHashOps.put(skuIdString,JSON.toJSONString(cart));
            });
            // 4.删除未登录的购物
            redisTemplate.delete(KEY_PREFIX+userKey);
            cartAsyncService.deleteCartByUserId(userKey);
        }
        // 5.查询登录状态的购物车并返回
        List<Object> loginCartJsons = loginHashOps.values();
        if (!CollectionUtils.isEmpty(loginCartJsons)) {
            return loginCartJsons.stream().map(Object->{
                Cart cart = JSON.parseObject(Object.toString(), Cart.class);
                cart.setCurrentPrice(new BigDecimal(redisTemplate.opsForValue().get(PRICE_PREFIX+cart.getSkuId())));
                return cart;

            }).collect(Collectors.toList());
        }
        return null;
    }

    
    public void updateNum(Cart cart) {
        String userId = getUserId();//getUserId()方法
        BigDecimal count = cart.getCount();
        String skuIdString = cart.getSkuId().toString();
        // 获取内层的map操作对象
        BoundHashOperations<String, Object, Object> hashOps =
                redisTemplate.boundHashOps(KEY_PREFIX+userId);
        if(hashOps.hasKey(cart.getSkuId().toString())){
            String cartJson = hashOps.get(skuIdString).toString();
             cart = JSON.parseObject(cartJson, Cart.class);
             cart.setCount(count);
            // 更新到数据库，redis mysql
            hashOps.put(skuIdString,JSON.toJSONString(cart));
            cartAsyncService.updateCart(userId,cart.getSkuId(),cart);
            return;
        }
        throw new CartException("该用户的购物车不包含该记录！");
    }

    public void deleteCart(Long skuId) {
        String userId = getUserId();
        BoundHashOperations<String, Object, Object> hashOps =
                redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (hashOps.hasKey(skuId.toString())) {
            hashOps.delete(skuId.toString());
            cartAsyncService.deleteCartByUserIdAndSkuId(userId,skuId);

        }
    }

//redis里的购物车是完整的，MySQL里可能缺少，而且操作redis更快
    public List<Cart> queryCheckedCarts(Long userId) {
        BoundHashOperations<String, Object, Object> hashOps =
                redisTemplate.boundHashOps(KEY_PREFIX + userId);
        List<Object> cartJsons = hashOps.values();
        if (!CollectionUtils.isEmpty(cartJsons)) {
            List<Cart> carts =
                    cartJsons.stream().map(Object -> JSON.parseObject(Object.toString(), Cart.class)).filter(Cart::getCheck).collect(Collectors.toList());
            return carts;
        }
        return null;
    }
}
